package cn.stylefeng.guns.modular.cb.service;

import cn.stylefeng.guns.modular.cb.config.OSSConfig;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.stream.FileImageOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
public class OSSService {

    private static Logger logger = LoggerFactory.getLogger(OSSService.class);

    /**
     * 文件落地目录
     */
    @Value("${file.landing.path}")
    private String fileLandingPath;

    private static Map<String, String> EXT_MAPS = new HashMap<>();

    // Endpoint以杭州为例，其它Region请按实际情况填写。
    private static String endpoint = OSSConfig.END_POINT;
//    // 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建RAM账号。
    private static String accessKeyId = OSSConfig.ACCESS_KEY_ID;
    private static String accessKeySecret = OSSConfig.ACCESS_KEY_SECRET;
    private static String bucketName = OSSConfig.BUCKET_NAME;

//    private static String endpoint = "http://oss-cn-beijing.aliyuncs.com";
//    private static String accessKeyId = "LTAI5t9K7HexsD1XTFkh7YVD";
//    private static String accessKeySecret = "rdGAx8bWe9xVkV6sov1VweBHWkUo7k";
//    private static String bucketName = "caibisystem";

    private static void init(){
        if (StringUtils.isEmpty(endpoint)){
            endpoint = OSSConfig.END_POINT;
        }
        if (StringUtils.isEmpty(accessKeyId)) {
            accessKeyId = OSSConfig.ACCESS_KEY_ID;
        }
        if (StringUtils.isEmpty(accessKeySecret)) {
            accessKeySecret = OSSConfig.ACCESS_KEY_SECRET;
        }
        if (StringUtils.isEmpty(bucketName)){
            bucketName = OSSConfig.BUCKET_NAME;
        }
    }
    /**
     * 上传文件
     *
     * @param file
     * @return
     */
    public String uploadOssFile(MultipartFile file) {
        init();
        try {
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            //上传文件的输入流
            InputStream inputStream = file.getInputStream();
            //获取文件名称
            String filename = file.getOriginalFilename();

            //生成唯一的文件名
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            filename = uuid + filename;

            //按日期文件夹分类
//            String datePath = new DateTime().toString("yyyy/MM/dd");;
//            filename=datePath+"/"+filename;

            // 创建PutObjectRequest对象。
            //第一个参数 Bucket名称
            //第二个参数 上传到oss文件路径和文件名称
            //第三个参数 上传文件输入流

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, filename, inputStream);

            // 如果需要上传时设置存储类型与访问权限，请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);

            // 上传文件。
            ossClient.putObject(putObjectRequest);

            // 关闭OSSClient。
            ossClient.shutdown();

            //把上传文件之后的路径返回
            String url = "";
            url = "http://" + OSSConfig.BUCKET_NAME + "." + OSSConfig.END_POINT + "/" + filename;
            return url;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 下载文件
     *
     * @param os
     * @param objectName
     */
    public void exportFile(OutputStream os, String objectName) {
        init();
        try {
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
            // 读取文件内容
            BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
            BufferedOutputStream out = new BufferedOutputStream(os);
            byte[] buffer = new byte[1024];
            int lenght;
            while ((lenght = in.read(buffer)) != -1) {
                out.write(buffer, 0, lenght);
            }
            out.flush();
        } catch (IOException e) {
            logger.error("Error occurred: {}", e.getMessage(), e);
        }
    }

    /**
     * 通过文件名下载文件
     *
     * @param fileNmae
     * @param localFileName
     */
    public void downloadFile(String fileNmae, String localFileName) {
        init();
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖，不存在则新建。
            ossClient.getObject(new GetObjectRequest(bucketName, fileNmae), new File(localFileName));
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    public byte[] streamFile(String objectName, HttpServletResponse response) {
        init();
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSObject ossObject = ossClient.getObject(bucketName, objectName);

        InputStream is = ossObject.getObjectContent();
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        try{
            while ((rc = is.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
        }catch (Exception e) {
            logger.error("streamFile error: ", e);
        }finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
        byte[] bytes = swapStream.toByteArray();

        // 读取文件内容。
//        System.out.println("Object content:");
//        BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
//        StringBuilder stringBuilder = new StringBuilder();
//        try {
//            while (true) {
//                String line = reader.readLine();
//                if (line == null) break;
//                System.out.println("\n" + line);
//                stringBuilder.append(line);
//            }
//        } catch (Exception e) {
//            logger.error("streamFile error ", e);
//        } finally {
//            // 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
//            try {
//                reader.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//            // 关闭OSSClient。
//            ossClient.shutdown();
//        }

        String contentType = EXT_MAPS.get(getFilenameSuffix(objectName));
        if (!StringUtils.isEmpty(contentType)) {
            response.setContentType(contentType);
            response.setContentLength(bytes.length);
        }
        return bytes;
    }

    /**
     * 下载文件
     * 文件落地，返回本地文件地址
     */
    public String downloadFile(String objectName){
        if (StringUtils.isEmpty(objectName)){
            return "";
        }
        String suffix = "doc";
        if(objectName.lastIndexOf(".") != -1 && objectName.lastIndexOf(".") != 0){
            suffix = objectName.substring(objectName.lastIndexOf(".")+1);
        }
        init();
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSObject ossObject = ossClient.getObject(bucketName, objectName);

        InputStream is = ossObject.getObjectContent();
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        try{
            while ((rc = is.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
        }catch (Exception e) {
            logger.error("streamFile error: ", e);
        }finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
        byte[] fileStream = swapStream.toByteArray();
        String path = fileLandingPath+ File.separator+ UUID.randomUUID()+"."+suffix;
        createDir(fileLandingPath);
        byte2image(fileStream, path);
        return path;
    }

    /**
     * 根据图片全路径删除就图片
     *
     * @param imgUrl   图片全路径
     */
    public void delImg(String imgUrl) {
        init();
        if (StringUtils.isEmpty(imgUrl)) {
            return;
        }
        //问号
        int index = imgUrl.indexOf("&#63;");
        if (index != -1) {
            imgUrl = imgUrl.substring(0, index);
        }
        int slashIndex = imgUrl.lastIndexOf('/');
        String fileId = imgUrl.substring(slashIndex + 1);
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.deleteObject(bucketName, fileId);
        ossClient.shutdown();
    }






    @Bean
    public String initExt() {
        EXT_MAPS.put("png", "image/png");
        EXT_MAPS.put("gif", "image/gif");
        EXT_MAPS.put("bmp", "image/bmp");
        EXT_MAPS.put("ico", "image/x-ico");
        EXT_MAPS.put("jpeg", "image/jpeg");
        EXT_MAPS.put("jpg", "image/jpeg");

        EXT_MAPS.put("zip", "application/zip");
        EXT_MAPS.put("rar", "application/x-rar");

        EXT_MAPS.put("pdf", "application/pdf");
        EXT_MAPS.put("ppt", "application/vnd.ms-powerpoint");
        EXT_MAPS.put("xls", "application/vnd.ms-excel");
        EXT_MAPS.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        EXT_MAPS.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
        EXT_MAPS.put("doc", "application/msword");
        EXT_MAPS.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        EXT_MAPS.put("txt", "text/plain");

        EXT_MAPS.put("mp4", "video/mp4");
        EXT_MAPS.put("flv", "video/x-flv");
        EXT_MAPS.put("wav", "audio/x-wav");
        return "";
    }

    public static String getFilenameSuffix(String filename) {
        String suffix = null;
        String originalFilename = filename;
        if (!StringUtils.isEmpty(filename)) {
            if (filename.contains("/")) {
                filename = filename.substring(filename.lastIndexOf("/") + 1);
            }
            if (filename.contains(".")) {
                suffix = filename.substring(filename.lastIndexOf(".") + 1);
            }
            else if (logger.isErrorEnabled()) {
                logger.error("filename error without suffix : {}", originalFilename);
            }
        }

        return suffix;
    }


    //byte数组到图片
    public void byte2image(byte[] data,String path){
        if(data.length<3||path.equals("")) return;
        try (FileImageOutputStream imageOutput = new FileImageOutputStream(new File(path));) {
            imageOutput.write(data, 0, data.length);
            imageOutput.close();
            logger.info("Make Picture success,Please find image in {}", path);
        } catch(Exception ex) {
            logger.error("Exception: " + ex);
        }
    }

    public void createDir(String dirPath){
        File folder = new File(dirPath);
        if (!folder.exists() && !folder.isDirectory()) {
            folder.mkdirs();
        }
    }
}
